﻿using System;
using System.Collections.Generic;
using System.Linq;
using SG.Lang.Dry.Code;
using SG.Lang.Dry.Mirrors;
using SG.Lang.Dry.Persistance;

namespace SG.Lang.Dry.Controlling
{
    public static class Resolver
    {
        public static Namespace ResolveNamespace(this Guid guid)
        {
            return Repository<Namespace, NamespaceRecord>.ResolveElement(ref guid, Namespace.Create);
        }

        public static Class ResolveClass(this Guid guid)
        {
            return Repository<Class, ADTRecord>.ResolveElement(ref guid, Class.Create);
        }

        public static Struct ResolveStruct(this Guid guid)
        {
            return Repository<Struct, ADTRecord>.ResolveElement(ref guid, Struct.Create);
        }

        public static Expression ResolveExpression(this Guid guid)
        {
            return guid.ResolveExpression<Expression>();
        }
        public static TExpression ResolveExpression<TExpression>(this Guid guid)
            where TExpression : Expression
        {
            return Repository<TExpression, ExpressionRecord>.ResolveElement(ref guid, ResolveExpression<TExpression>);
        }

        private static TExpression ResolveExpression<TExpression>(ref ElementRecord elementrecord, ref ExpressionRecord specific)
            where TExpression : Expression
        {
            // TODO: store expression kind
            throw new NotImplementedException();
        }

        public static Property ResolveProperty(this Guid guid)
        {
            return Repository<Property, PropertyRecord>.ResolveElement(ref guid, Property.Create);
        }

        public static Field ResolveField(this Guid guid)
        {
            return Repository<Field, FieldRecord>.ResolveElement(ref guid, Field.Create);
        }

        public static TypeRef ResolveType(this Guid guid)
        {
            return Repository<TypeRef, TypeRefRecord>.ResolveElement(ref guid, TypeRef.Create);
        }

        private static IEnumerable<Guid> Nodes(ref ItemList itemList)
        {
            return itemList.Nodes(ResolveItemListNode);
        }

        public static bool ResolveItemListNode(this Guid guid, out ItemList node)
        {
            return ResolveItemListNode(ref guid, out node);
        }
        private static bool ResolveItemListNode(ref Guid guid, out ItemList node)
        {
            if (guid == Guid.Empty || !Repository<ItemList>.TryGet(ref guid, out node))
            {
                node = default(ItemList);
                return false;
            }

            return true;
        }

        public static IEnumerable<Field> ResolveFields(this ItemList fields)
        {
            return Nodes(ref fields).Select(ResolveField);
        }

        public static IEnumerable<Property> ResolveProperties(this ItemList properties)
        {
            return Nodes(ref properties).Select(ResolveProperty);
        }

        public static IEnumerable<TypeRef> ResolveTypes(this ItemList properties)
        {
            return Nodes(ref properties).Select(ResolveType);
        }

        public static IEnumerable<Expression> ResolveExpressions(this ItemList properties)
        {
            return properties.ResolveExpressions<Expression>();
        }
        public static IEnumerable<TExpression> ResolveExpressions<TExpression>(this ItemList properties)
            where TExpression : Expression
        {
            return Nodes(ref properties).Select(ResolveExpression<TExpression>);
        }

    }
}
